Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

Implement Pretty Formatting Option for CREATE TABLE Statements

Summary

Added a new pretty formatting option to the PostgreSQL deparser that enables multi-line formatting for CREATE TABLE statements with proper newlines and indentation. This feature makes generated SQL more readable while maintaining full backward compatibility.

Changes Made

Core Implementation

  • Enhanced DeparserOptions interface: Added pretty?: boolean option (defaults to false)
  • Extended SqlFormatter class: Added pretty mode support with proper indentation logic
  • Modified CreateStmt method: Implemented multi-line formatting when pretty=true
  • Maintained backward compatibility: All existing functionality unchanged when pretty=false

New Test Infrastructure

  • Created pretty/ test folder: New test directory at packages/deparser/__tests__/pretty/
  • Added snapshot tests: Comprehensive test coverage using Jest snapshots
  • Created test fixtures: Sample CREATE TABLE statements in __fixtures__/pretty/

Technical Details

Pretty Formatting Logic

When pretty: true is enabled, CREATE TABLE statements are formatted as:

CREATE TABLE users (
  id serial PRIMARY KEY,
  name text NOT NULL,
  email text UNIQUE
);

Instead of the default single-line format:

CREATE TABLE users (id serial PRIMARY KEY, name text NOT NULL, email text UNIQUE);

Implementation Highlights

  1. SqlFormatter enhancements:

    • Added prettyMode flag and isPretty() method
    • Implemented proper indent() method that actually performs indentation
    • Support for custom newline and tab characters
  2. CreateStmt modifications:

    • Conditional formatting based on pretty mode
    • Proper indentation for column definitions and constraints
    • Newlines after opening parenthesis and before closing parenthesis
  3. Configurable formatting:

    • Custom newline characters (default: '\n')
    • Custom tab characters (default: ' ')
    • Pretty mode toggle (default: false)

Test Results

New Pretty Formatting Tests

  • ✅ Basic CREATE TABLE with pretty formatting
  • ✅ Complex CREATE TABLE with constraints and foreign keys
  • ✅ Single-line format maintained when pretty=false
  • ✅ Custom newline and tab character support
  • ✅ All 5 snapshot tests passing

Backward Compatibility

  • ✅ All existing 255 test suites continue to pass
  • ✅ 272 total tests passing
  • ✅ No regressions in existing functionality
  • ✅ Default behavior unchanged (pretty=false)

Usage Examples

import { deparseSync } from '@pgsql/deparser';
import { parse } from 'libpg-query';

const sql = 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL);';
const parsed = await parse(sql);

// Pretty formatting enabled
const prettyResult = deparseSync(parsed, { pretty: true });
// Output:
// CREATE TABLE users (
//   id serial PRIMARY KEY,
//   name text NOT NULL
// );

// Default single-line format
const defaultResult = deparseSync(parsed, { pretty: false });
// Output: CREATE TABLE users (id serial PRIMARY KEY, name text NOT NULL);

// Custom formatting options
const customResult = deparseSync(parsed, { 
  pretty: true, 
  newline: '\r\n', 
  tab: '    ' 
});

Future Extensibility

The infrastructure added for pretty formatting can be easily extended to support other SQL statement types (INSERT, UPDATE, SELECT, etc.) by following the same pattern in their respective deparser methods.

Verification

cd packages/deparser
yarn build  # ✅ Build successful
yarn test   # ✅ 255/255 test suites passing, 272/272 tests passing
yarn test --testNamePattern="Pretty CREATE TABLE formatting"  # ✅ 5/5 snapshot tests passing

Link to Devin run

https://app.devin.ai/sessions/e2a49c9a83094092a217b1c66ad778de

Requested by: Dan Lynch ([email protected])

devin-ai-integration bot and others added 13 commits June 23, 2025 05:50
- Add pretty option to DeparserOptions interface
- Enhance SqlFormatter with proper indentation support
- Modify CreateStmt to format with newlines and tabs when pretty=true
- Create new pretty/ test folder with snapshot tests
- Maintain backward compatibility (pretty=false by default)
- All existing tests continue to pass

Co-Authored-By: Dan Lynch <[email protected]>
…atements

- Add pretty formatting for SELECT statements with proper clause indentation
- Add pretty formatting for constraint statements with multi-line support
- Add pretty formatting for CREATE POLICY statements with clause formatting
- Create comprehensive test fixtures for all new statement types
- Add snapshot tests for SELECT, constraints, and CREATE POLICY formatting
- Maintain backward compatibility with single-line formatting when pretty=false
- All tests passing with proper snapshot validation

Co-Authored-By: Dan Lynch <[email protected]>
- Remove extra blank lines after SELECT keyword
- Fix indentation levels for FROM, LIMIT, OFFSET clauses
- Add AST validation test to ensure pretty-formatted SQL maintains semantic equivalence
- Update snapshots to match correct formatting pattern
- All pretty formatting tests now pass (SELECT, CREATE TABLE, constraints, CREATE POLICY)

Co-Authored-By: Dan Lynch <[email protected]>
- Replace custom AST validation logic with proper expectAstMatch utility from test-utils
- Update all pretty formatting tests (SELECT, CREATE TABLE, constraints, CREATE POLICY) to use expectAstMatch
- Fix CreatePolicyStmt deparser bug that was removing spaces between keywords in pretty mode
- Ensure round-trip validation: parse(sql1) → deparse(ast) → sql2 where parse(sql1) === parse(sql2) at AST level
- Update CREATE POLICY snapshots to reflect corrected formatting
- All tests pass with proper semantic equivalence validation

Co-Authored-By: Dan Lynch <[email protected]>
…comparison

- Add standalone expectParseDeparse helper function in test-utils/index.ts (not on class)
- Implement round-trip validation: parse(sql1) → deparse(sql2) → parse(sql2) → compare cleanTree(ast1) vs cleanTree(ast2)
- Replace expectAstMatch usage with expectParseDeparse in all pretty formatting tests:
  - SELECT pretty tests
  - CREATE TABLE pretty tests
  - Constraints pretty tests
  - CREATE POLICY pretty tests
- Use direct expect(ast2).toEqual(ast1) comparison for semantic validation
- All tests pass with simplified, more direct AST validation approach

Co-Authored-By: Dan Lynch <[email protected]>
- Update expectParseDeparse to return deparsed SQL for snapshot testing
- Add DeparserOptions type support for newline and tab options
- Replace all deparseSync calls with expectParseDeparse in pretty tests
- Remove separate AST validation tests - now consolidated into snapshot tests
- Each test now gets both AST validation and snapshot testing in single call
- All 4 pretty test suites (24 tests, 24 snapshots) pass with consolidated approach

Co-Authored-By: Dan Lynch <[email protected]>
- Remove unnecessary if/else conditionals where both branches do identical operations
- Simplify LIMIT and OFFSET logic while maintaining functionality
- Both pretty and non-pretty modes now use the same streamlined code path
- All tests continue to pass with simplified logic

Co-Authored-By: Dan Lynch <[email protected]>
- Add newline formatting for JOIN clauses in SELECT statements
- Improve CREATE POLICY formatting with proper USING and WITH CHECK clause indentation
- Implement CTE (Common Table Expressions) pretty formatting with proper indentation
- Add comprehensive test cases for complex SQL formatting scenarios
- Update snapshots to reflect improved formatting output
- Maintain AST equivalence through expectParseDeparse validation

Co-Authored-By: Dan Lynch <[email protected]>
…able aliases

- Fixed JoinExpr method to properly handle spaces in pretty formatting mode
- Added leading space to ON and USING clauses to maintain proper SQL syntax
- Updated snapshots to reflect improved formatting that matches Dan's requirements
- All tests passing with enhanced JOIN, CREATE POLICY, and CTE formatting

Co-Authored-By: Dan Lynch <[email protected]>
- Add containsMultilineStringLiteral helper method to detect multi-line string literals
- Preserve string literal content in SelectStmt target lists, GROUP BY, HAVING, ORDER BY clauses
- Fix WithClause CTE formatting to avoid corrupting string literals during indentation
- Resolves all 6 failing kitchen sink tests while maintaining AST equivalence

Co-Authored-By: Dan Lynch <[email protected]>
- Add detailed pretty formatting section to DEPARSER_USAGE.md
- Include complete options table with all 5 available options
- Provide clear examples for basic usage and custom formatting
- Document supported statements and semantic preservation notes
- Complete the pretty formatting feature documentation

Co-Authored-By: Dan Lynch <[email protected]>
- Add concise Options section with table of main options
- Include pretty formatting example showing before/after
- Reference full documentation in DEPARSER_USAGE.md
- Complete user-facing documentation for pretty print feature

Co-Authored-By: Dan Lynch <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants